package world.snowcrystal.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import lombok.extern.log4j.Log4j2;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import world.snowcrystal.exception.SnowcrystalInvalidTokenException;
import world.snowcrystal.exception.SnowcrystalTokenExpiredException;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Log4j2
public class JwtUtils {

    final static String SECRET = "hsadiufsdhvidufhvbuds";
    public static String AUTHENTICATION_COOKIE_NAME = "X-Snowcrystal-Camellia";

    /**
     * in milliseconds
     *
     * @since 1.0
     **/
    public final static long EXPIRATION = Long.MAX_VALUE;
    final static String LOCAL_ISSUER = "www.snowcrystal.world";
    final static Set<String> audiences = Set.of("www.snowcrystal.world", "www.snowcrystal.cn");

    final static Verification require = JWT.require(Algorithm.HMAC384(SECRET));

    public static String makeJWT(String username, String password) {
        Assert.hasText(username, "Token Computation : Username must not be null or blank");
        Assert.hasText(password, "Token Computation : Password must not be null or blank");
        JWTCreator.Builder builder = JWT.create();
        final long current = System.currentTimeMillis();
        builder.withIssuer(LOCAL_ISSUER)
                .withSubject("www.snowcrystal.world")
                .withAudience(StringUtils.toStringArray(audiences))
                .withIssuedAt(new Date(current))
//                .withExpiresAt(new Date(current+ EXPIRATION))
                .withClaim("username", username)
                .withClaim("password", password);
        return builder.sign(Algorithm.HMAC384(SECRET));
    }


    /**
     * 返回 Token 中保存的用户名与密码信息
     *
     * @param token 前端发来的 Token
     * @author tianqing
     * @see JWTVerifier#verify(String)
     * @since 1.0
     **/
    public static Map<String, String> verifyJWT(String token)
            throws TokenExpiredException,
            AlgorithmMismatchException, SignatureVerificationException {

        Assert.hasText(token, "token must not be null or blank");
        require.ignoreIssuedAt()
                .withIssuer(LOCAL_ISSUER);
        JWTVerifier build = require.build();
        DecodedJWT verify = build.verify(token);
        Map<String, String> map = new HashMap<>();
        map.put("username", verify.getClaim("username").asString());
        map.put("password", verify.getClaim("password").asString());
        return map;
    }

    public static String[] verifyJwt(String token) throws SnowcrystalTokenExpiredException,
            SnowcrystalInvalidTokenException {
        Assert.hasText(token, "token must not be null or blank");
        require.ignoreIssuedAt()
                .withIssuer(LOCAL_ISSUER);

        JWTVerifier build = require.build();
        DecodedJWT verify = null;
        try{

             verify = build.verify(token);
        }catch (TokenExpiredException e){
            throw new SnowcrystalTokenExpiredException("Token expired");
        } catch (AlgorithmMismatchException  | SignatureVerificationException e){
                throw new SnowcrystalInvalidTokenException("Token mismatch");
        }
        return new String[]{verify.getClaim("username").asString(),
                verify.getClaim("password").asString()};
    }


}